const puppeteer = require('puppeteer');
const cheerio = require('cheerio');
const url = require('url');
const downImg = require('./downImg');
const sendrequest = require('./sendRequest');
const {
  findDB,
  createOneDB,
  bulkAddArticle,
  someAddArticle,
  oneUpdateArticle,
  someUpdateArticle
} = require('../../models/article');

// 爬虫规则配置项
// const config = {
//   baseURL: 'https://ent.163.com/tv',
//   query: {}, // 查询参数  ?aa=bb
//   pathname: '', // 路径名 /aa/cc/a.html
//   nextURL: '.news_article .news_title h3 a',
// 存在则进行查找下一条数据
//   next: [
//     {
//       selector: {
//         title: '.post_title',
//         content: '#content .post_body'
//       }
//     }
//   ]
// };

const config = {
  catid: 81,
  description: '网易新闻-音乐',
  baseURL: 'https://ent.163.com/music',
  nextURL: '.ndi_main .news_article .news_title h3 a',
  next: {
    selector: {
      title: 'h1',
      content: '#content .post_body'
    },
    $afterContentHook($) {}
  },
  pushAddress: 'http://www.rssso.com/api/CmsPost/Publish',
  $globalStartDispose($) {
    $('div>img').remove();
  }
};

// 处理爬虫路径
function handleUrlPath(pathUrl) {
  if (!pathUrl) return '';
  if (pathUrl.startsWith('http') || pathUrl.startsWith('https')) {
    return pathUrl; // 网络绝对路径
  } else if (pathUrl.startsWith('//')) {
    const urlObj = url.parse(config.baseURL, true);
    return urlObj?.protocol + pathUrl;
  } else {
    const urlObj = url.parse(config.baseURL, true);
    return (
      urlObj?.protocol + '//' + urlObj?.host + (pathUrl.startsWith('/') ? pathUrl : '/' + pathUrl)
    );
  }
}

// 处理文本中图片
async function handleTextImgUrl(text) {
  if (typeof text !== 'string' && text) return;
  // 进行替换(思路一：方法如下匹配到图标标签并且地址同时清除)
  // text = text.replace(/<img [^>]*src=['"]([^'"]+)[^>]*>/gi, function ($1, $2) {
  // $1 匹配整个元素  $2 匹配第一个括号匹配的字符串(也就是图片地址)
  // 处理图片地址进行下载(返回地址)
  //   try {
  //     const newImg = ''; // 适用于替换为固定图片
  //     return $1.replace($2, newImg); // 注意这里是不能进行异步函数的，替换时不能获取到等待的结果
  //   } catch (err) {
  //     console.log(err);
  //     return ''; // 整个图片标签都去除
  //   }
  // });
  // 进行替换(思路二：匹配出图片标签过滤字符串，再定义正则匹配图片标签地址替换 replace 方法是不会改变原数据)
  const imgObj = []; // 存放图片标签元素
  text.replace(/<img [^>]*src=['"]([^'"]+)[^>]*>/gi, function ($1, $2) {
    imgObj.push({ $1, $2 });
  });
  // let index = 0;
  // const len = imgObj.length;
  // if (len > 0) {
  //   await replaceImgUrl(imgObj[index]);
  // }
  // 递归方法进行
  // async function replaceImgUrl(imgInfo) {
  //   const imgurl = imgInfo.$2; // 网络图片地址
  //   try {
  //     const newUrl = await downImg(imgurl);
  //     text = text.replace(imgurl, newUrl);
  //   } catch (err) {
  //     console.log(err);
  //     text = text.replace(imgInfo.$1, ''); // 图片标签都替换掉
  //   } finally {
  //     index++;
  //     if (index < len) {
  //       replaceImgUrl(imgObj[index]);
  //     } else {
  //       console.log(text, 333);
  //     }
  //   }
  // }
  for (const imgInfo of imgObj) {
    try {
      const imgurl = imgInfo.$2;
      const newUrl = await downImg(imgurl.replace(/&amp;/gi, '&')); // 传入的地址先将 & 转义回来
      text = text.replace(imgurl, newUrl);
    } catch (e) {
      text = text.replace(imgInfo.$1, '');
      console.error(e);
    }
  }
  return Promise.resolve(text);
}

// 处理详情页面
function disposeChild(nextPageUrl, options) {
  console.log('开始处理文章详情页');
  if (!nextPageUrl.length) {
    return console.log('未找到文章列表');
  }
  let index = 0;
  const len = nextPageUrl.length && 10;
  reptile(nextPageUrl[index].url, options);
  async function reptile(url, options) {
    if (!url) return;
    // 判断是否处理过
    const isProcessed = await findDB(url);
    if (isProcessed) {
      console.log('已处理忽略', url);
      index++;
      if (index < len) {
        reptile(nextPageUrl[index].url, options);
      } else {
        console.log('处理完成');
      }
    } else {
      console.log('正在处理的文章的址', url);
      try {
        const $ = await common(handleUrlPath(url));
        // 未处理文本前勾子函数
        config.$globalStartDispose &&
          typeof config.$globalStartDispose === 'function' &&
          config.$globalStartDispose($);
        const { selector, $afterContentHook } = options;
        if (selector) {
          const article = { url, catid: config.catid };
          for (let item in selector) {
            if (selector[item]) {
              if (item === 'content') {
                article[item] = $(selector[item]).prop('outerHTML');
              } else {
                article[item] = $(selector[item]).text();
              }
            }
          }
          if (article.content) {
            article.content = await handleTextImgUrl(article.content); // 处理内容中图片
            const $ = cheerio.load(article.content);
            $afterContentHook && typeof $afterContentHook === 'function' && $afterContentHook($);
          }
          if (!article.desc && article.content) {
            article.desc = (
              cheerio.load(article.content).text().trim().slice(0, 120) + '...'
            ).trim();
          }
          console.log(article, 343);
          const isUploadSuccess = await sendrequest(article);
          if (isUploadSuccess) {
            console.log('上传成功');
          } else {
            console.log('上传失败');
          }
          // 写入数据库
          createOneDB(article);
        }
      } catch (err) {
        console.log(err);
      } finally {
        index++;
        if (index < len) {
          reptile(nextPageUrl[index].url, options);
        } else {
          console.log('处理完成');
        }
      }
    }
  }
}

// 公共部位
async function common(url) {
  const browser = await puppeteer.launch({ headless: true, timeout: 5000 }); // 开启浏览器 （默认是不打开浏览器）
  const page = await browser.newPage(); // 打开新页面
  await page.goto(handleUrlPath(url)); // 爬取地址
  // await page.reload(); // 重新加载
  let body = await page.$eval('body', el => el.outerHTML); // 获取文本
  const $ = cheerio.load(body);
  await browser.close(); // 关闭浏览器
  return $; // 转化为 jq 语法
}

// 爬虫主入口
async function reptileMain(config) {
  console.log('爬虫配置项', config);
  try {
    const $ = await common(config.baseURL);
    // 未处理文本前勾子函数
    config.$globalStartDispose &&
      typeof config.$globalStartDispose === 'function' &&
      config.$globalStartDispose($);
    const nextURL = config['nextURL'];
    // 查找下一页
    if (nextURL) {
      let nextPageUrl = []; // 获取详情页列表
      $(nextURL).each(function () {
        if ($(this).prop('href')) {
          nextPageUrl.push({ url: $(this).prop('href') });
        }
      });
      console.log('文章列表地址', nextPageUrl);
      config.next && disposeChild(nextPageUrl, config.next); // 详情页
    } else {
      // 当前页面最终页面，处理查找页面数据
      //
    }
  } catch (err) {
    console.log('网络异常,ip可能被封', err);
  }
}

// 导出接口
module.exports = (req, res) => {
  reptileMain(config);
  res.send('hello world');
};

// 测试代码
async function test(config) {
  const browser = await puppeteer.launch({ headless: false }); // 开启浏览器 （默认是不打开浏览器）
  const page = await browser.newPage(); // 打开新页面
  await page.goto('https://ent.163.com/tv'); // 爬取地址
  // 获取文本(方法一)
  // const bodyHandle = await page.$('body');
  // const html = await page.evaluate(body => body.innerHTML, bodyHandle);
  // console.log(html);
  // 获取文本(方法二)
  // const body = await page.$eval('body', el => el.outerHTML);
  // console.log(body);
  // js 获取节点(函数中代码都是运行在浏览器中)
  const title2 = await page.evaluate(() => {
    // 此处代码运行是在浏览器中（也就是这里写代码等同于在浏览器控制台中书写代码）
    const keys = Object.keys(config);
    console.log(keys, 2223); //! 报错 (注意获取不到上面数据 config 因为这数据在 node 而这里数据在浏览器)
    const titleDom = document.querySelector('title'); // js 获取元素
    console.log(titleDom); // 无头浏览器控台中输出
    return titleDom.innerText;
  });
  console.log(title2); // node 环境输出
  const result = await page.evaluate(x => {
    console.log(location.reload());
    console.log(x); // node 传入的数据
    return Promise.resolve(8 * x);
  }, 7); // 第二参数为传递给
  console.log(result); // 输出 "56"
  // await browser.close(); // 关注浏览器
}

// const text =
//   '<div class="post_body"><img src="https://nimg.ws.126.net/?url=http%3A%2F%2Fdingyue.ws.126.net%2F2022%2F1022%2Fe76039bfj00rk5wfq0234d000v901bup.jpg&thumbnail=660x2147483647&quality=80&type=jpg"><h3>HELLO WORLD</h3></h3><img src="https://nimg.ws.126.net/?url=http%3A%2F%2Fdingyue.ws.126.net%2F2022%2F1022%2Fe76039bfj00rk5wfq0234d000v901bup.jpg&thumbnail=660x2147483647&quality=80&type=jpg"></div>';
// async function cc() {
//   const x = await handleTextImgUrl(text);
//   console.log(x, 4958);
// }
// cc();
